#include "SoundHardware.h"
#include "Common.h"

#include <memory>
#include <cassert>
#include <cstring>

SoundHardware::SoundHardware(const byte_t * soundRegistersPtr)
	: m_registers(soundRegistersPtr)
{
	byte_t soundPROMData[0x100];

	LoadRomFile("rom/82s126.1m", soundPROMData, 0x100);

	m_soundPROM = new sword_t [256];
	for (size_t i = 0; i < 256; ++i)
		m_soundPROM[i] = static_cast<sword_t>(soundPROMData[i]) - 8;
	
	memset(m_counters, 0, sizeof(unsigned int) * 3);
}

SoundHardware::~SoundHardware()
{
	delete[] m_soundPROM;
}

void SoundHardware::Play(sword_t * buffer, size_t size, size_t sampleRate)
{
	for (size_t i = 0; i < 3; ++i)
	{
		byte_t freqAddr, volumeAddr, waveformAddr;
		freqAddr = volumeAddr = waveformAddr = 0;
		
		switch (i)
		{
		case 0: freqAddr = 0x10; volumeAddr = 0x15; waveformAddr = 0x05; break;
		case 1: freqAddr = 0x15; volumeAddr = 0x1A; waveformAddr = 0x0A; break;
		case 2: freqAddr = 0x1A; volumeAddr = 0x1F; waveformAddr = 0x0F; break;
		}

		unsigned int f;
		f =            (m_registers[freqAddr + 4] & 0x0F);
		f = (f << 4) | (m_registers[freqAddr + 3] & 0x0F);
		f = (f << 4) | (m_registers[freqAddr + 2] & 0x0F);
		f = (f << 4) | (m_registers[freqAddr + 1] & 0x0F);
		f = (f << 4);
		
		if (i == 0) f |= (m_registers[freqAddr + 0] & 0x0F);

		byte_t volume = m_registers[volumeAddr] & 0x0F;
		byte_t waveform = m_registers[waveformAddr] & 7;

		size_t offset = m_counters[i];
		size_t offset_step = f * ( (96000 << 10) / sampleRate );
		const sword_t * data = m_soundPROM + waveform * 32;

		if (volume > 0 && f > 0)
		{
			for (size_t j = 0; j < size; j++) 
			{
				sword_t dat = data[(offset >> 25) & 0x1F];
				//buffer[j]	+= static_cast<sword_t>(32760 * (float)(dat) / (float)(0x0F));
			
				double val = (double)dat / 8.0;
				double vol = (double)volume / 16.0;
				double asd = vol * val;

				buffer[j]	+= static_cast<sword_t>(32768.0 * 0.1 * asd);
				offset		+= offset_step;
			}
		}

		m_counters[i] = offset;
	}
}
